#include "mlir/IR/DialectRegistry.h"
#include "mlir/Tools/mlir-opt/MlirOptMain.h"
// 导入 Func Dialect
#include "mlir/Dialect/Func/IR/FuncOps.h"
// 导入 MLIR 自带 Pass
#include "mlir/Transforms/Passes.h"
// 导入我们新建的 Dialect
#include "toy/ToyDialect.h"
#include "toy/ToyOps.h"

#include "mlir/IR/AsmState.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Visitors.h"
//#include "mlir/IR/OperationSupport.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/Parser/Parser.h"
#include "mlir/Support/FileUtilities.h"

#include "mlir/Dialect/Arith/IR/Arith.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ArrayRef.h"

#include <iostream>

using namespace mlir;
using namespace llvm;

int main(int argc, char ** argv) {
  MLIRContext ctx;

  ctx.loadDialect<toy::ToyDialect, func::FuncDialect>();
  OpBuilder builder(&ctx);
  auto mod = builder.create<ModuleOp>(builder.getUnknownLoc());
  builder.setInsertionPointToEnd(mod.getBody());
  
  auto i32 = builder.getI32Type();
  auto funcType = builder.getFunctionType({i32, i32}, {i32});
  OperationState func_state(builder.getUnknownLoc(), toy::FuncOp::getOperationName());
  func_state.addAttribute(SymbolTable::getSymbolAttrName(), builder.getStringAttr("test_add"));
  func_state.addAttribute(toy::FuncOp::getFunctionTypeAttrName(func_state.name), TypeAttr::get(funcType));
  
  Region *bodyRegion = func_state.addRegion();
  Block *body = new Block();
  bodyRegion->push_back(body);

  auto inputTypes = funcType.getInputs();
  for (Type input : inputTypes) {
    body->addArgument(input, func_state.location);
  }

  auto* op = builder.create(func_state);
  auto func_op = dyn_cast<toy::FuncOp>(op);

  
  auto entry_block = func_op->getRegions().begin();
  /*
  auto args = entry_block->getArguments();
  builder.setInsertionPointToEnd(entry_block);

  OperationState state(builder.getUnknownLoc(), toy::SubOp::getOperationName());
  state.addTypes(builder.getI32Type());
  state.addOperands({args[0], args[1]});

  auto* sub_op = builder.create(state);
  auto subi = dyn_cast<toy::SubOp>(sub_op);
  */

  /*
  // 创建 func
  auto i32 = builder.getI32Type();
  auto funcType = builder.getFunctionType({i32, i32}, {i32});
  auto func = builder.create<func::FuncOp>(builder.getUnknownLoc(), "fuck", funcType);

  
  // 添加基本块
  auto entry = func.addEntryBlock();
  auto args = entry->getArguments();

  builder.setInsertionPointToEnd(entry);

  OperationState const_state(builder.getUnknownLoc(), toy::ConstantOp::getOperationName());
  
  OperationState state(builder.getUnknownLoc(), toy::SubOp::getOperationName());
  state.addTypes(builder.getI32Type());
  state.addOperands({args[0], args[1]});
  

  auto* op = builder.create(state);

  auto addi = dyn_cast<toy::SubOp>(op);

  // 创建 func.return
  builder.create<func::ReturnOp>(builder.getUnknownLoc(), ValueRange({addi}));
  */
  mod->print(llvm::outs());
  
  return 0;
}
